package com.ruoyi.business.customer.service.impl;


import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.base.JoBaseServiceImpl;
import com.ruoyi.business.base.PageParam;
import com.ruoyi.business.customer.domain.JbCustomer;
import com.ruoyi.business.customer.domain.JbFollowupEvaluation;
import com.ruoyi.business.customer.domain.JbFollowupRecord;
import com.ruoyi.business.customer.domain.dto.JbFollowupRecordDto;
import com.ruoyi.business.customer.domain.dto.JbFollowupRecordListDto;
import com.ruoyi.business.customer.domain.vo.JbFollowListVo;
import com.ruoyi.business.customer.domain.vo.JbFollowupEvaluationVo;
import com.ruoyi.business.customer.domain.vo.JbFollowupRecordExportListVo;
import com.ruoyi.business.customer.domain.vo.JbFollowupRecordListVo;
import com.ruoyi.business.customer.mapper.JbFollowupRecordMapper;
import com.ruoyi.business.customer.service.JbCustomerService;
import com.ruoyi.business.customer.service.JbFollowupEvaluationService;
import com.ruoyi.business.customer.service.JbFollowupRecordService;
import com.ruoyi.business.sundry.domain.JbBusinessOperRecord;
import com.ruoyi.business.sundry.domain.JbNotification;
import com.ruoyi.business.sundry.service.JbBusinessOperRecordService;
import com.ruoyi.business.sundry.service.JbNotificationService;
import com.ruoyi.business.sundry.service.SysDataScopeFactoryService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BusinessOperModule;
import com.ruoyi.common.enums.RoleEnum;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.impl.SysUserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.SecurityUtils.getLoginUser;

/**
 * 跟进记录Service业务层处理
 *
 * @author ruoyi
 * @date 2024-10-11
 */
@Service
@Slf4j
public class JbFollowupRecordServiceImpl
        extends JoBaseServiceImpl<JbFollowupRecordMapper, JbFollowupRecord>
        implements JbFollowupRecordService
{
    @Autowired
    private SysUserServiceImpl sysUserService;
    @Autowired
    private JbCustomerService jbCustomerService;
    @Autowired
    private JbFollowupEvaluationService jbFollowupEvaluationService;
    @Autowired
    private JbBusinessOperRecordService jbBusinessOperRecordService;
    @Autowired
    private ISysDictDataService sysDictDataService;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private JbNotificationService jbNotificationService;
    @Autowired
    private SysDataScopeFactoryService sysDataScopeFactoryService;

    @Override
    public IPage<JbFollowupRecordListVo> listData(IPage page, JbFollowupRecordListDto jbFollowupRecord)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        LambdaQueryWrapper<JbFollowupRecord> select = new LambdaQueryWrapper<>();
        SysUser user = getLoginUser().getUser();
        select.eq(ObjectUtils.isNotEmpty(jbFollowupRecord.getStaffId()), JbFollowupRecord::getStaffId, jbFollowupRecord.getStaffId());
        select.eq(StringUtils.isNotBlank(jbFollowupRecord.getTaskStatus()), JbFollowupRecord::getTaskStatus,
                        jbFollowupRecord.getTaskStatus())
                .eq(ObjectUtils.isNotEmpty(jbFollowupRecord.getFollowupType()), JbFollowupRecord::getFollowupType,
                        jbFollowupRecord.getFollowupType())
                .ge(StringUtils.isNotBlank(jbFollowupRecord.getStartTime()), JbFollowupRecord::getFollowupTime,
                        jbFollowupRecord.getStartTime())
                .le(StringUtils.isNotBlank(jbFollowupRecord.getEndTime()), JbFollowupRecord::getFollowupTime,
                        jbFollowupRecord.getEndTime())
                .ge(ObjectUtils.isNotEmpty(jbFollowupRecord.getDataType()), JbFollowupRecord::getDataType,
                        jbFollowupRecord.getDataType())
                .eq(ObjectUtils.isNotEmpty(jbFollowupRecord.getCustomerId()), JbFollowupRecord::getCustomerId,
                        jbFollowupRecord.getCustomerId());

        select.orderByDesc(JbFollowupRecord::getId);
        //角色数据权限
        List<Long> roleData=sysDataScopeFactoryService.fnListDataScope(Constants.PUBLIC_NUMBER_0.toString());
        select.in(ObjectUtils.isNotEmpty(roleData), JbFollowupRecord::getStaffId, roleData);
        List<JbFollowupRecord> jbFollowupRecords = this.list(page, select);
        List<JbFollowupRecordListVo> vos = Lists.newArrayList();
        if (ObjectUtils.isNotEmpty(jbFollowupRecords))
        {
            List<Long> collect =
                    jbFollowupRecords.stream().map(JbFollowupRecord::getStaffId).collect(Collectors.toList());
            List<Long> customerIds =
                    jbFollowupRecords.stream().map(JbFollowupRecord::getCustomerId).collect(Collectors.toList());
            List<JbCustomer> jbCustomers = jbCustomerService.listByIds(customerIds);
            Map<Long, String> customerMap = jbCustomers.stream().collect(Collectors.toMap(JbCustomer::getId,
                    JbCustomer::getCustomerName));
            List<SysUser> list = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getUserId,
                    collect).select(SysUser::getUserId, SysUser::getUserName));
            Map<Long, SysUser> collect1 = list.stream().collect(Collectors.toMap(SysUser::getUserId,
                    Function.identity()));
            jbFollowupRecords.forEach(a ->
            {
                JbFollowupRecordListVo vo = new JbFollowupRecordListVo();
                BeanUtils.copyProperties(a, vo);
                SysUser sysUser = collect1.get(a.getStaffId());
                if (ObjectUtils.isNotEmpty(sysUser))
                {
                    vo.setStaffName(sysUser.getUserName());
                    vo.setAvatar(sysUser.getAvatar());
                }
                vo.setCustomerName(customerMap.get(a.getCustomerId()));
                vos.add(vo);
            });
        }
        IPage<JbFollowupRecordListVo> pageVo = new Page<>();
        BeanUtils.copyProperties(page, pageVo);
        pageVo.setRecords(vos);
        return pageVo;
    }

    @Override
    public List<JbFollowupRecord> listDayData(JbFollowupRecordListDto jbFollowupRecord)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        QueryWrapper<JbFollowupRecord> select = new QueryWrapper<>();
        select.select("DATE_FORMAT(followup_time, '%Y-%m-%d') AS followupTime");
        // LambdaQueryWrapper<JbFollowupRecord> select = new LambdaQueryWrapper<>();
        SysUser user = getLoginUser().getUser();
        //自己
        select.lambda().eq(JbFollowupRecord::getStaffId, user.getUserId());
        select.lambda().eq(ObjectUtils.isNotEmpty(jbFollowupRecord.getStaffId()), JbFollowupRecord::getStaffId, jbFollowupRecord.getStaffId())
                .eq(StringUtils.isNotBlank(jbFollowupRecord.getTaskStatus()), JbFollowupRecord::getTaskStatus,
                        jbFollowupRecord.getTaskStatus())
                .eq(ObjectUtils.isNotEmpty(jbFollowupRecord.getFollowupType()), JbFollowupRecord::getFollowupType,
                        jbFollowupRecord.getFollowupType())
                .ge(StringUtils.isNotBlank(jbFollowupRecord.getStartTime()), JbFollowupRecord::getFollowupTime,
                        jbFollowupRecord.getStartTime())
                .le(StringUtils.isNotBlank(jbFollowupRecord.getEndTime()), JbFollowupRecord::getFollowupTime,
                        jbFollowupRecord.getEndTime())
                .ge(ObjectUtils.isNotEmpty(jbFollowupRecord.getDataType()), JbFollowupRecord::getDataType,
                        jbFollowupRecord.getDataType())
                .eq(ObjectUtils.isNotEmpty(jbFollowupRecord.getCustomerId()), JbFollowupRecord::getCustomerId,
                        jbFollowupRecord.getCustomerId());
        select.last(" and followup_time is not null group by  followupTime ");
        List<JbFollowupRecord> jbFollowupRecords = list(select);
        return jbFollowupRecords;
    }

    @Override
    @Transactional
    public Boolean saveInfo(JbFollowupRecordDto jbFollowupRecordDto)
    {
        JbFollowupRecord record = new JbFollowupRecordDto();
        BeanUtils.copyProperties(jbFollowupRecordDto, record);
        record.setDataType(Constants.PUBLIC_NUMBER_1);
        String content = dynamicDataContent(jbFollowupRecordDto.getDynamicData());
        record.setFollowupContent(content);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (ObjectUtils.isEmpty(jbFollowupRecordDto.getStaffId()))
        {
            record.setStaffId(loginUser.getUserId());
        }
        this.save(record);
        Long recordId = record.getId();
        if (ObjectUtils.isNotEmpty(jbFollowupRecordDto.getNextFollowupRecord()))
        {
            //添加下次计划
            record = new JbFollowupRecordDto();
            BeanUtils.copyProperties(jbFollowupRecordDto.getNextFollowupRecord(), record);
            record.setDataType(Constants.PUBLIC_NUMBER_0);
            record.setCustomerId(jbFollowupRecordDto.getCustomerId());
            record.setTaskStatus(Constants.JBFOLLOWUPRECORD_TASKSTATUS_1001);
            this.save(record);
        }

        if (ObjectUtils.isNotEmpty(jbFollowupRecordDto.getParentId()))
        {
            //更新跟进计划的状态为已完成
            JbFollowupRecordDto updateParent = new JbFollowupRecordDto();
            updateParent.setId(jbFollowupRecordDto.getParentId());
            updateParent.setTaskStatus(Constants.JBFOLLOWUPRECORD_TASKSTATUS_1002);
            this.updateById(updateParent);
        }
        //添加了跟进记录才算最后跟进时间
        JbCustomer customer = new JbCustomer();
        customer.setId(record.getCustomerId());
        customer.setLatestFollowupTime(new Date());
        jbCustomerService.updateById(customer);
        //处理客户动态的标题
        setBusinessOperRecord(recordId, content, Constants.PUBLIC_NUMBER_1, jbFollowupRecordDto);
        return true;
    }

    @Override
    public JbFollowupRecordListVo getDataInfo(Long id)
    {
        JbFollowupRecord byId = this.getById(id);
        JbFollowupRecordListVo listVo = new JbFollowupRecordListVo();
        BeanUtils.copyProperties(byId, listVo);
        JbCustomer customer = jbCustomerService.getById(byId.getCustomerId());
        listVo.setCustomerName(Optional.ofNullable(customer).map(JbCustomer::getCustomerName).orElse(StringUtils.EMPTY));
        SysUser one = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getUserId,
                byId.getStaffId()).select(SysUser::getUserName));
        listVo.setStaffName(Optional.ofNullable(one).map(SysUser::getUserName).orElse(StringUtils.EMPTY));
        long count =
                jbFollowupEvaluationService.count(Wrappers.lambdaQuery(JbFollowupEvaluation.class).eq(JbFollowupEvaluation::getRecordId, id));
        listVo.setCommentNumber((int) count);
        return listVo;
    }

    @Override
    public IPage<JbFollowupRecordListVo> recordList(IPage page, JbFollowupRecordListDto jbFollowupRecord)
    {

        StringJoiner joiner = new StringJoiner(" ").add("""
                SELECT
                	fr.id,
                	fr.followup_type,
                	fr.followup_content,
                	fr.dynamic_data,
                	fr.customer_status,
                	fr.followup_method,
                	fr.create_time,
                	fr.create_time,
                	fr.create_by,
                	fr.staff_id,
                	fr.followup_time,
                	fr.customer_id,
                	jc.customer_name AS customerName,
                	su.user_name staffName,
                	su.avatar
                FROM
                	jb_followup_record fr
                	LEFT JOIN sys_user su ON fr.staff_id = su.user_id
                	INNER JOIN jb_customer jc ON fr.customer_id = jc.id\s
                WHERE
                	fr.del_flag = '0'\s
                	AND fr.data_type = 1
                """);
        joiner.add(joSqlUtil.sqlIf("and fr.staff_id='#{staffId}'", jbFollowupRecord.getStaffId()));
        joiner.add(joSqlUtil.sqlIf("and fr.task_status='#{taskStatus}'", jbFollowupRecord.getTaskStatus()));
        joiner.add(joSqlUtil.sqlIf("and fr.followup_type='#{followupType}'", jbFollowupRecord.getFollowupType()));
        joiner.add(joSqlUtil.sqlIf("and INSTR(fr.followup_content,'#{keywords}')>0 ", jbFollowupRecord.getKeywords()));
        joiner.add(joSqlUtil.sqlIf("and fr.followup_time>='#{startTime}'", jbFollowupRecord.getStartTime()));
        joiner.add(joSqlUtil.sqlIf("and fr.followup_time<='#{endTime}'", jbFollowupRecord.getEndTime()));
        joiner.add(joSqlUtil.sqlIf("and fr.customer_id='#{customerId}'", jbFollowupRecord.getCustomerId()));
        joiner.add(joSqlUtil.sqlIf("and jc.customer_name='#{customerName}'", jbFollowupRecord.getCustomerName()));
        joiner.add(joSqlUtil.sqlIf("and jc.parent_id='#{parentId}'", jbFollowupRecord.getParentId()));
        joiner.add(joSqlUtil.sqlIf("and su.dept_id='#{deptId}'", jbFollowupRecord.getDeptId()));
        //角色数据权限
        String roleData=sysDataScopeFactoryService.fnStrDataScope(Constants.PUBLIC_NUMBER_0.toString());
        if (StrUtil.isNotBlank(roleData))
        {
            joiner.add(String.format(" and fr.staff_id in (%s)", roleData));
        }
        joiner.add(" order by fr.id desc ");
        String sqlStr = joSqlUtil.sqlJson(joiner.toString(), jbFollowupRecord);
        IPage<JbFollowupRecordListVo> pageVo = joSqlUtil.jsonToEntity(baseMapper.pageJson(page, sqlStr),
                JbFollowupRecordListVo.class);
        if (ObjectUtils.isNotEmpty(pageVo) && ObjectUtils.isNotEmpty(pageVo.getRecords()))
        {
            String collect = pageVo.getRecords().stream().map(a -> a.getId().toString()).collect(Collectors.joining(
                    ","));
            joiner = new StringJoiner(" ")
                    .add("""
                                   select fe.id,fe.record_id,fe.comment_content,fe.create_time,su.user_name as createName from jb_followup_evaluation fe 
                                  left JOIN sys_user su on su.user_id=fe.create_by  where  fe.del_flag='0'
                            """);
            joiner.add(" and fe.record_id in (" + collect + ") order by fe.id desc");
            List<JbFollowupEvaluationVo> jbFollowupEvaluationVos =
                    joSqlUtil.jsonToEntity(baseMapper.findJson(joiner.toString()), JbFollowupEvaluationVo.class);
            if (ObjectUtils.isNotEmpty(jbFollowupEvaluationVos))
            {
                Map<Long, List<JbFollowupEvaluationVo>> commMap =
                        jbFollowupEvaluationVos.stream().collect(Collectors.groupingBy(JbFollowupEvaluationVo::getRecordId));
                pageVo.getRecords().forEach(a ->
                {
                    List<JbFollowupEvaluationVo> jbFollowupEvaluationVos1 = commMap.get(a.getId());
                    a.setCommentList(jbFollowupEvaluationVos1);
                    a.setCommentNumber(ObjectUtils.isNotEmpty(jbFollowupEvaluationVos1) ?
                            jbFollowupEvaluationVos1.size() : Constants.PUBLIC_NUMBER_0);
                });
            }
        }
        return pageVo;
    }

    @Override
    public List<JbFollowupRecordExportListVo> exportRecord(IPage page, JbFollowupRecordListDto jbFollowupRecord)
    {
        List<JbFollowupRecordExportListVo> exportList = Lists.newArrayList();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        StringJoiner joiner = new StringJoiner(" ").add("""
                SELECT
                	fr.id AS id,
                	fr.dynamic_data AS dynamicData,
                	fr.followup_time AS followupTime,
                	jc.customer_name AS customerName,
                	su.user_name staffName\s
                	,(select count(1) from jb_followup_evaluation fe where fe.del_flag='0' and fe.record_id=fr.id) as commentNumber
                  ,(select dict_label from sys_dict_data where dict_type='bus_followup_type' and dict_value=fr.followup_type LIMIT 1) as followupType
                FROM
                	jb_followup_record fr
                	LEFT JOIN sys_user su ON fr.staff_id = su.user_id
                	LEFT JOIN jb_customer jc ON fr.customer_id = jc.id\s
                WHERE
                	fr.del_flag = '0'\s
                	AND fr.data_type = 1
                """);
        SysUser user = getLoginUser().getUser();
        joiner.add(joSqlUtil.sqlIf("and fr.staff_id='#{staffId}'", jbFollowupRecord.getStaffId()));
        joiner.add(joSqlUtil.sqlIf("and fr.task_status='#{taskStatus}'", jbFollowupRecord.getTaskStatus()));
        joiner.add(joSqlUtil.sqlIf("and fr.followup_type='#{followupType}'", jbFollowupRecord.getFollowupType()));
        joiner.add(joSqlUtil.sqlIf("and INSTR(fr.followup_content,'#{keywords}')>0 ", jbFollowupRecord.getKeywords()));
        joiner.add(joSqlUtil.sqlIf("and fr.followup_time>='#{startTime}'", jbFollowupRecord.getStartTime()));
        joiner.add(joSqlUtil.sqlIf("and fr.followup_time<='#{endTime}'", jbFollowupRecord.getEndTime()));
        joiner.add(joSqlUtil.sqlIf("and fr.customer_id='#{customerId}'", jbFollowupRecord.getCustomerId()));
        //角色数据权限
        String roleData=sysDataScopeFactoryService.fnStrDataScope(Constants.PUBLIC_NUMBER_0.toString());
        if (StrUtil.isNotBlank(roleData))
        {
            joiner.add(String.format(" and fr.staff_id in (%s)", roleData));
        }
        joiner.add(" order by fr.id desc ");
        String sqlStr = joSqlUtil.sqlJson(joiner.toString(), jbFollowupRecord);
        if (jbFollowupRecord.getExportType().equals(Constants.PUBLIC_NUMBER_1))
        {
            List<JbFollowupRecordExportListVo> jbFollowupRecordExportListVos =
                    joSqlUtil.jsonToEntity(baseMapper.findJson(sqlStr), JbFollowupRecordExportListVo.class);
            exportList = jbFollowupRecordExportListVos;
        } else
        {
            IPage<JbFollowupRecordExportListVo> pageVo = joSqlUtil.jsonToEntity(baseMapper.pageJson(page, sqlStr),
                    JbFollowupRecordExportListVo.class);
            if (ObjectUtils.isNotEmpty(pageVo) && ObjectUtils.isNotEmpty(pageVo.getRecords()))
            {
                exportList = pageVo.getRecords();
            }
        }
        if (ObjectUtils.isNotEmpty(exportList))
        {
            exportList.stream().forEach(a ->
            {
                StringBuilder builder = new StringBuilder();
                String dynamicData = a.getDynamicData();
                if (StringUtils.isNotBlank(dynamicData))
                {
                    JSONArray jsonArray = JSONArray.parseArray(dynamicData);
                    jsonArray.forEach(data ->
                    {
                        String content = ((JSONObject) data).getString(Constants.FOLLOWUP_RECORD_CONTENT);
                        if (StringUtils.isNotBlank(content))
                        {
                            builder.append(content);
                        }
                    });
                }
                a.setDynamicData(builder.toString());
            });
        }

        return exportList;
    }

    @Override
    @Transactional
    public Boolean updateInfo(JbFollowupRecordDto jbFollowupRecordDto)
    {

        JbFollowupRecord record = new JbFollowupRecordDto();
        BeanUtils.copyProperties(jbFollowupRecordDto, record);
        record.setDataType(Constants.PUBLIC_NUMBER_1);
        String content = dynamicDataContent(jbFollowupRecordDto.getDynamicData());
        record.setFollowupContent(content);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (ObjectUtils.isEmpty(jbFollowupRecordDto.getStaffId()))
        {
            record.setStaffId(loginUser.getUserId());
        }
        this.updateById(record);
        Long recordId = record.getId();
        if (ObjectUtils.isNotEmpty(jbFollowupRecordDto.getNextFollowupRecord()))
        {
            record = new JbFollowupRecordDto();
            BeanUtils.copyProperties(jbFollowupRecordDto.getNextFollowupRecord(), record);
            record.setDataType(Constants.PUBLIC_NUMBER_0);
            record.setCustomerId(jbFollowupRecordDto.getCustomerId());
            this.save(record);
        }
        setBusinessOperRecord(recordId, content, Constants.PUBLIC_NUMBER_2, jbFollowupRecordDto);
        return true;
    }

    @Override
    @Transactional
    public Boolean removeRecord(Long id)
    {
        JbFollowupRecord byId = this.getById(id);
        String content = dynamicDataContent(byId.getDynamicData());
        boolean b = this.removeById(id);
        JbFollowupRecordDto jbFollowupRecordDto = new JbFollowupRecordDto();
        BeanUtils.copyProperties(byId, jbFollowupRecordDto);
        setBusinessOperRecord(id, content, Constants.PUBLIC_NUMBER_3, jbFollowupRecordDto);
        return b;
    }

    @Override
    public Boolean taskStatus()
    {
        long currentTime = System.currentTimeMillis();
        log.info("===========自动更新跟进计划状态-{},{}", LocalDateTime.now());
        //小于当前时间，且是未开始的，把状态修改为未完成
        List<JbFollowupRecord> jbFollowupRecords =
                list(Wrappers.lambdaQuery(JbFollowupRecord.class).eq(JbFollowupRecord::getDataType,
                                Constants.PUBLIC_NUMBER_0)
                        .eq(JbFollowupRecord::getTaskStatus, Constants.JBFOLLOWUPRECORD_TASKSTATUS_1001)
                        .lt(JbFollowupRecord::getFollowupTime, new Date()));
        if (ObjectUtils.isNotEmpty(jbFollowupRecords))
        {
            List<JbFollowupRecord> update = Lists.newArrayList();
            jbFollowupRecords.forEach(a ->
            {
                JbFollowupRecord fr = new JbFollowupRecord();
                fr.setId(a.getId());
                fr.setTaskStatus(Constants.JBFOLLOWUPRECORD_TASKSTATUS_1003);
                update.add(fr);
            });
            log.info("===========自动更新跟进计划状态-{}", update);
            updateBatchById(update);
        }
        log.info("===========自动更新跟进计划状态-{},{}", LocalDateTime.now(), System.currentTimeMillis() - currentTime);
        return null;
    }

    @Override
    public Boolean remind()
    {
        //20秒执行一次
        String redisKey = Constants.RULE_REDIS_KEY + Constants.FOLLOWUPRECORDTASK_REMIND;
        Boolean b = redisCache.hasKey(redisKey);
        if (b)
        {
            //执行频率高，存在表示上次还没有执行完。
            return true;
        }
        redisCache.setCacheObject(redisKey, DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, new Date()),
                Constants.PUBLIC_NUMBER_2, TimeUnit.DAYS);
        try
        {
            //系统消息,未提交或者已完成（是添加了跟进记录）的计划，判断是否要提前提醒
            List<JbFollowupRecord> jbFollowupRecords =
                    list(Wrappers.lambdaQuery(JbFollowupRecord.class).eq(JbFollowupRecord::getDataType,
                                    Constants.PUBLIC_NUMBER_0)
                            .eq(JbFollowupRecord::getReminderMethod, Constants.JBFOLLOWUPRECORD_TASKSTATUS_1001)
                            .isNull(JbFollowupRecord::getNotificationId)
                            .eq(JbFollowupRecord::getTaskStatus, Constants.JBFOLLOWUPRECORD_TASKSTATUS_1001));
//               .and(a -> a.eq(JbFollowupRecord::getTaskStatus, Constants.JBFOLLOWUPRECORD_TASKSTATUS_1001)
//                .or().eq(JbFollowupRecord::getTaskStatus, Constants.JBFOLLOWUPRECORD_TASKSTATUS_1002))
            // reminderType 提前几分钟 bus_followup_task

            //1001 提前5分钟,1002 提前15分钟,1003 提前30分钟,1004 提前1小时,1005 提前2小时,1006 准时提醒
            if (ObjectUtils.isNotEmpty(jbFollowupRecords))
            {
                for (JbFollowupRecord record : jbFollowupRecords)
                {
                    Date followupTime = record.getFollowupTime();
                    Date now = new Date();
                    String reminderType = record.getReminderType();
                    long diffInMillis = 0;
                    boolean isNotificationId = false;
                    switch (reminderType)
                    {
                        case Constants.CUSTOMER_TYPE_1006:
                            //准时提醒
                            diffInMillis = now.getTime() - followupTime.getTime();
                            if (TimeUnit.MILLISECONDS.toMinutes(diffInMillis) == 0)
                            {
                                //到时间
                                isNotificationId = true;
                            }

                            break;
                        case Constants.CUSTOMER_TYPE_1001:
                            //提前5分钟
                            now = DateUtils.addMinutes(now, 5);
                            diffInMillis = now.getTime() - followupTime.getTime();
                            if (TimeUnit.MILLISECONDS.toMinutes(diffInMillis) == 0)
                            {
                                //到时间
                                isNotificationId = true;
                            }
                            break;
                        case Constants.CUSTOMER_TYPE_1002:
                            //提前15分钟
                            now = DateUtils.addMinutes(now, 15);
                            diffInMillis = now.getTime() - followupTime.getTime();
                            if (TimeUnit.MILLISECONDS.toMinutes(diffInMillis) == 0)
                            {
                                //到时间
                                isNotificationId = true;
                            }
                            break;
                        case Constants.CUSTOMER_TYPE_1003:
                            //提前30分钟
                            now = DateUtils.addMinutes(now, 30);
                            diffInMillis = now.getTime() - followupTime.getTime();
                            if (TimeUnit.MILLISECONDS.toMinutes(diffInMillis) == 0)
                            {
                                //到时间
                                isNotificationId = true;
                            }
                            break;
                        case Constants.CUSTOMER_TYPE_1004:
                            //提前1小时
                            now = DateUtils.addHours(now, 1);
                            diffInMillis = now.getTime() - followupTime.getTime();
                            if (TimeUnit.MILLISECONDS.toHours(diffInMillis) == 0)
                            {
                                //到时间
                                isNotificationId = true;
                            }
                            break;
                        case Constants.CUSTOMER_TYPE_1005:
                            //提前2小时
                            now = DateUtils.addHours(now, 2);
                            diffInMillis = now.getTime() - followupTime.getTime();
                            if (TimeUnit.MILLISECONDS.toHours(diffInMillis) == 0)
                            {
                                //到时间
                                isNotificationId = true;
                            }
                            break;

                        default:
                    }
                    if (isNotificationId)
                    {
                        //到时间提醒
                        try
                        {
                            insertNotification(record);
                        } catch (Exception ex)
                        {
                            log.error("==跟进计划提醒插入通知异常", ex);
                        }
                    }
                }
            }
        } finally
        {
            redisCache.deleteObject(redisKey);
        }
        return null;
    }

    @Override
    public IPage<JbFollowListVo> followupList(PageParam pageParam, JbFollowupRecord jbFollowupRecord)
    {
        StringJoiner sql=new StringJoiner(" ").add("""
                SELECT
                	jc.customer_name,
                	jfr.*\s
                FROM
                	jb_followup_record jfr
                	INNER JOIN jb_customer jc ON jfr.customer_id = jc.id\s
                WHERE
                	jfr.del_flag = 0\s
                	AND jc.del_flag = 0\s
                """);
        sql.add(joSqlUtil.sqlIf(" AND jfr.data_type =#{dataType}", jbFollowupRecord.getDataType()));
        //角色数据权限
        String roleData=sysDataScopeFactoryService.fnStrDataScope(Constants.PUBLIC_NUMBER_0.toString());
        if (StrUtil.isNotBlank(roleData))
        {
            sql.add(String.format(" AND jfr.staff_id in (%s)", roleData));
        }
        sql.add(" ORDER BY jfr.id DESC ");
        String s = joSqlUtil.sqlJson(sql.toString(), jbFollowupRecord);
        IPage<JbFollowListVo> page = joSqlUtil.jsonToEntity(baseMapper.pageJson(pageParam.b(), s), JbFollowListVo.class);
        if (ObjectUtils.isNotEmpty(page) && ObjectUtils.isNotEmpty(page.getRecords()))
        {
            page.getRecords().forEach(a ->{
                 //状态是未完成
                if (Constants.CUSTOMER_TYPE_1003.equals(a.getTaskStatus()))
                {
                    //计算当前时间减去跟进时间得到天数
                    a.setOvertimeDay(DateUtils.differentDaysByMillisecond(a.getFollowupTime(),new Date()));
                }
            });
        }
        return page;
    }

    @Transactional(propagation = Propagation.NESTED)
    public void insertNotification(JbFollowupRecord record)
    {

        log.info("===========跟进计划提醒-{},{}", LocalDateTime.now());
        JbNotification notification = new JbNotification();
        notification.setDataType(Constants.PUBLIC_NUMBER_3);
        notification.setSenderId(-666L);
        notification.setSenderName("系统");
        notification.setRecipientId(record.getStaffId());
        notification.setTitle(StringUtils.format("您的跟进计划【{}】即将到期，请尽快处理!", record.getFollowupContent()));
        notification.setContent(record.getFollowupContent());
        notification.setSendTime(new Date());
        notification.setOperModuleId(record.getId().toString());
        jbNotificationService.save(notification);
        JbFollowupRecord update = new JbFollowupRecord();
        update.setId(record.getId());
        update.setNotificationId(notification.getId());
        boolean b = updateById(update);
        log.info("===========跟进计划提醒结束-{},{},{}", LocalDateTime.now(), b, record.getId());
    }


    /**
     * 解析动态数据存到内容字段
     *
     * @param dynamicData
     * @return
     */
    private String dynamicDataContent(String dynamicData)
    {
        StringBuilder builder = new StringBuilder();
        if (StringUtils.isNotBlank(dynamicData))
        {
            JSONArray jsonArray = JSONArray.parseArray(dynamicData);
            jsonArray.forEach(data ->
            {
                String content = ((JSONObject) data).getString(Constants.FOLLOWUP_RECORD_CONTENT);
                if (StringUtils.isNotBlank(content))
                {
                    builder.append(content);
                }
            });
        }
        return builder.toString();
    }

    /**
     * 设置操作日志
     *
     * @param recordId
     * @param content
     * @param businessType
     * @param jbFollowupRecordDto
     */
    private void setBusinessOperRecord(Long recordId, String content, Integer businessType,
                                       JbFollowupRecordDto jbFollowupRecordDto)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        StringBuilder title = new StringBuilder();
        //处理客户动态的标题
        if (businessType.equals(Constants.PUBLIC_NUMBER_3))
        {
            title.append("删除记录");
        } else
        {
            String fllowupTypeName = sysDictDataService.selectDictLabel("bus_followup_type",
                    jbFollowupRecordDto.getFollowupType());
            String customerStatusName = sysDictDataService.selectDictLabel("bus_customer_status",
                    jbFollowupRecordDto.getCustomerStatus());

            title.append(Optional.ofNullable(customerStatusName).orElse(StringUtils.EMPTY));
            if (StringUtils.isNotBlank(customerStatusName))
            {
                title.append("(").append(fllowupTypeName).append(")");
            }
        }
        //添加客户动态的标题
        JbBusinessOperRecord jbBusinessOperRecord = new JbBusinessOperRecord();
        jbBusinessOperRecord.setTitle(title.toString());
        jbBusinessOperRecord.setTitleCode(jbFollowupRecordDto.getFollowupType());
        jbBusinessOperRecord.setTitleCodeTwo(jbFollowupRecordDto.getCustomerStatus());
        jbBusinessOperRecord.setModuleName(BusinessOperModule.CUSTOMER_DYNAMIC.getInfo());
        jbBusinessOperRecord.setModuleCode(BusinessOperModule.CUSTOMER_DYNAMIC.getCode());
        jbBusinessOperRecord.setSubModuleCode(BusinessOperModule.CUSTOMER_FOLLOWUP.getCode());
        jbBusinessOperRecord.setRecordId(jbFollowupRecordDto.getCustomerId());
        jbBusinessOperRecord.setBusinessId(jbFollowupRecordDto.getStaffId());
        jbBusinessOperRecord.setContent(content);
        jbBusinessOperRecord.setOtherRecordId(recordId);
        jbBusinessOperRecord.setBusinessType(businessType);
        jbBusinessOperRecord.setMethod(ServletUtils.getRequest().getRequestURI());
        jbBusinessOperRecord.setOperatorType(Constants.PUBLIC_NUMBER_1);
        jbBusinessOperRecord.setCreateName(loginUser.getUsername());
        jbBusinessOperRecordService.save(jbBusinessOperRecord);
    }
}
